﻿using ArtMath.Flag;
using ArtMath.CommonType;
using ArtMath.Resource;
using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace ArtMath.Command
{
    /// <summary>
    /// 表示恢复图形或动画的命令
    /// </summary>
    /// <typeparam name="T">可恢复对象</typeparam>
    public class RecoverObjects<T> : CommandBase where T : IRecoverableDelete
    {
        IList<T> objs;
        public event Action<ICollection<T>> DeleteObject, RecoverObject;
        public RecoverObjects(IList<T> objs)
        {
            this.objs = objs;
            string[] names = new string[objs.Count];
            for (int i = 0; i < names.Length; i++)
            {
                names[i] = objs[i].Name;
            }
            UndoMenuItem = new ToolStripMenuItem($"{Resources.Translate("Delete")} {ZipName(names)}")
            {
                ToolTipText = $"{Resources.Translate("Delete")} {ZipName(names, names.Length)}",
            };
            RedoMenuItem = new ToolStripMenuItem($"{Resources.Translate("Recover")} {ZipName(names)}")
            {
                ToolTipText = $"{Resources.Translate("Recover")} {ZipName(names, names.Length)}",
            };
        }
        public override int ObjectCount
        {
            get { return objs.Count; }
        }
        public void RemoveObjects(Predicate<T> judge)
        {
            if (judge == null) return;
            List<string> names = new List<string>();
            for (int i = objs.Count - 1; i >= 0; i--)
            {
                if (judge(objs[i]))
                {
                    objs.RemoveAt(i);
                }
                else
                {
                    names.Add(objs[i].Name);
                }
            }
            UndoMenuItem.Text = $"{Resources.Translate("Delete")} {ZipName(names)}";
            UndoMenuItem.ToolTipText = $"{Resources.Translate("Delete")} {ZipName(names, names.Count)}";
            RedoMenuItem.Text = $"{Resources.Translate("Recover")} {ZipName(names)}";
            RedoMenuItem.ToolTipText = $"{Resources.Translate("Recover")} {ZipName(names, names.Count)}";
        }
        public override void Redo()
        {
            if (RecoverObject == null)
            {
                HashSet<T> recoveredObjs = new HashSet<T>();
                foreach (T item in objs)
                {
                    try
                    {
                        item.Recover();
                        if (item.ObjectState == ObjectState.Normal)
                        {
                            recoveredObjs.Add(item);
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        break;
                    }
                    catch (Exception ex)
                    {
                        ex.Data.Add("RecoveredObjects", recoveredObjs);
                        throw ex;
                    }
                }
                if (recoveredObjs.Count < objs.Count)
                {
                    Exception ex = new Exception(Flags.ExceptionShieldMessage);
                    ex.Data.Add("RecoveredObjects", recoveredObjs);
                    throw ex;
                }
            }
            else
            {
                RecoverObject(objs);
            }
        }

        public override void Undo()
        {
            if (DeleteObject == null)
            {
                HashSet<T> deletedObjs = new HashSet<T>();
                foreach (T item in objs)
                {
                    try
                    {
                        item.Delete(true);
                        if (item.ObjectState == ObjectState.Deleted)
                        {
                            deletedObjs.Add(item);
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        break;
                    }
                    catch (Exception ex)
                    {
                        ex.Data.Add("DeletedObjects", deletedObjs);
                        throw ex;
                    }
                }
                if (deletedObjs.Count < objs.Count)
                {
                    Exception ex = new Exception(Flags.ExceptionShieldMessage);
                    ex.Data.Add("DeletedObjects", deletedObjs);
                    throw ex;
                }
            }
            else
            {
                DeleteObject(objs);
            }
        }
    }
}
